home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’95 / Venus / image.h < prev    next >
Text File  |  1995-06-23  |  17KB  |  533 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *               Grayscale Image
  6.  *
  7.  *   The image is represented as a Pixmap, i.e. a matrix of pixels
  8.  *    each of them specifies the gray level at a particular point
  9.  *
  10.  *    The header file defines arithmetical and all other operations
  11.  *          permitted on the grayscale image
  12.  *
  13.  * $Id: image.h,v 1.11 1993/05/28 14:34:42 oleg Exp oleg $
  14.  *
  15.  ************************************************************************
  16.  */
  17.  
  18. #pragma once
  19. #ifndef _image_h
  20. #define _image_h
  21.  
  22. #ifdef __GNUC__
  23. #pragma interface
  24. #endif
  25.  
  26. #include "myenv.h"
  27.  
  28. typedef unsigned short GRAY;        // Pixel type
  29. typedef signed short GRAY_SIGNED;    // Pixel type, signed
  30. const int GRAY_MAXBIT = 8*sizeof(GRAY);    // Max no of bits per pixel
  31. const int GRAY_MAXVAL = ((1<<GRAY_MAXBIT)-1);
  32.  
  33. class Rectangle;
  34. class rowcol;
  35. class Extrema;
  36.  
  37. typedef int USER_F(int);        // User function that can be applied
  38.                     // to the image
  39.  
  40. class IMAGE
  41. {
  42.   friend class Rectangle;
  43.   friend class Extrema;
  44.   
  45. private:            // Private part
  46.   int valid_code;            // Validation code
  47.   #define IMAGE_val_code 577767    // Image validation code
  48.   int ncols;                // Image width in pixels
  49.   int nrows;                // Image height in pixels
  50.   int npixels;                // Total no of pixels in the image
  51.   char * name;                // Image name
  52.   int bits_per_pixel;            // Image depth
  53.   GRAY ** scanrows;            // scanrows[i] = &pixels[i,0]
  54.   GRAY * pixels;            // pixels[i,j] is the
  55.                       // pixel value at point (i,j)
  56.                     // Pixels are ordered in rows
  57.  
  58.   void allocate(const int nrows, const int ncols, const int depth);
  59.  
  60.   void _expand(const IMAGE& prototype);    // Expand the prototype twice
  61.   void _shrink(const IMAGE& prototype);    // Shrink the prototype twice
  62.  
  63. public:            // Public interface
  64.   
  65.                 // Constructors and destructors
  66.                       // Make a blank image
  67.   IMAGE(const int nrows, const int ncols, const int depth);
  68.   IMAGE(const IMAGE &image);        // Make a new blank image like 
  69.                       // the old one
  70.                     // Read an image from the file
  71.   IMAGE(const char * file_name,const char print_header_info = 0);
  72.   IMAGE(const Rectangle& area);    // Make an image from a square area
  73.                     // of another image
  74.  
  75.                     // Construct an image applying a spec
  76.                     // operation to the prototype
  77.   enum IMAGE_CREATORS_1op { Expand, Shrink };
  78.   IMAGE(const IMAGE_CREATORS_1op op, const IMAGE& prototype);
  79.  
  80.   ~IMAGE();
  81.  
  82.   void is_valid() const
  83.   { assure(valid_code == IMAGE_val_code,"Invalid image"); }
  84.  
  85.                 // Status
  86.   int q_nrows() const            { return nrows; }
  87.   int q_ncols()    const            { return ncols; }
  88.   int q_depth()    const            { return bits_per_pixel; }
  89.   int q_npixels() const            { return npixels; }
  90.   const char * q_name() const          { return name; } 
  91.  
  92.                 // Individual pixel manipulations
  93.   inline GRAY& operator () (const int row, const int col) const;
  94.   inline GRAY& operator () (const rowcol pos) const;
  95.   void  sure_within(const rowcol pos) const;    // Make sure the pos
  96.                         // is within the image
  97.  
  98. // Row Column, Square operations
  99.  
  100.                 // Image-scalar operations
  101.  
  102.                 // Find out if the predicate
  103.                 // "(signed)pixel op val" is true for ALL
  104.                 // pixels of the image?
  105.   int operator ==  (const int val) const;    // ? (signed)pixels == val
  106.   int operator !=  (const int val) const;    // ? (signed)pixels != val
  107.   int operator <   (const int val) const;    // ? (signed)pixels <  val
  108.   int operator <=  (const int val) const;    // ? (signed)pixels <= val
  109.   int operator >   (const int val) const;    // ? (signed)pixels >  val
  110.   int operator >=  (const int val) const;    // ? (signed)pixels >= val
  111.  
  112.                 // Modify every element of the
  113.                 // image according to the operation
  114.   IMAGE& operator =   (const int val);        // Assignment to all the pixels
  115.   IMAGE& operator -=  (const int val);        // Diminish the brightness
  116.   IMAGE& operator +=  (const int val);        // Increase the brightness
  117.   IMAGE& operator *=  (const int val);
  118.   IMAGE& operator |=  (const int val);        // OR
  119.   IMAGE& operator &=  (const int val);        // AND
  120.   IMAGE& operator ^=  (const int val);        // XOR
  121.   IMAGE& operator <<= (const int val);        // Shift all the pixels
  122.   IMAGE& operator >>= (const int val);        // Shift all the pixels
  123.  
  124.  
  125.                 // Single image operations
  126.   IMAGE& clear(void);            // Clear the image
  127.   IMAGE& invert(void);            // Invert the image
  128.   IMAGE& abs(void);            // pixel = |(signed)pixel|
  129.   IMAGE& clip_to_intensity_range(void); // Clip pixel values to
  130.                     // [0,1<<bits_per_pixel-1]
  131.   IMAGE& normalize_for_display(void);    // Normalize pixel values to be
  132.                     // in range 0..1<<bits_per_pixel-1
  133.   IMAGE& equalize(const int no_grays);  // Perform the histogram equalization
  134.   IMAGE& apply(USER_F * fp);        // Apply any function defined for
  135.                     // a pixel to all pixels in the image
  136.  
  137.                 // Estimate the norm of the (signed) image
  138.   double norm_1(void)     const;    // SUM{ |(signed)pixel[i,j]| }
  139.   double norm_2_sqr(void) const;    // SUM{ (signed)pixel[i,j]^2 }
  140.   int    norm_inf(void)   const;    // MAX{ |(signed)pixel[i,j]| }
  141.  
  142.                 // Two images operations
  143.   IMAGE& operator = (const IMAGE& source);    // Assignment
  144.  
  145.   friend int  identical(const IMAGE& im1, const IMAGE& im2);
  146.   friend inline int  operator == (const IMAGE& im1, const IMAGE& im2);    // Alias
  147.   friend void compare(const IMAGE& im1, const IMAGE& im2, 
  148.               const char * title);
  149.   friend inline void are_compatible(const IMAGE& im1, const IMAGE& im2);
  150.  
  151.  
  152.                           // Arithmetics
  153.   friend IMAGE& operator += (IMAGE& target, const IMAGE& source);
  154.   friend IMAGE& operator -= (IMAGE& target, const IMAGE& source);
  155.   friend IMAGE& add(IMAGE& target, const int scalar,const IMAGE& source);
  156.                         // Shift the source to 'pos'
  157.                         // clip if necessary
  158.                         // multiply by scalar
  159.                         // and add
  160.   IMAGE& shift_clip_add(rowcol pos, const int scalar, const IMAGE& source);
  161.  
  162.                         // Logic
  163.   friend IMAGE& operator |= (IMAGE& target, const IMAGE& source);
  164.   friend IMAGE& operator &= (IMAGE& target, const IMAGE& source);
  165.   friend IMAGE& operator ^= (IMAGE& target, const IMAGE& source);
  166.  
  167.                         // Scalar product
  168.   friend double operator * (const IMAGE& im1, const IMAGE& im2);
  169.  
  170.                 // Estimate the norm of the difference 
  171.                 // between two (signed) image
  172.                     // SUM{ |(signed)pixel[i,j]| }
  173.   friend double norm_1(const IMAGE& im1, const IMAGE& im2);
  174.                     // SUM{ (signed)pixel[i,j]^2 }
  175.   friend double norm_2_sqr(const IMAGE& im1, const IMAGE& im2);
  176.                     // MAX{ |(signed)pixel[i,j]| }
  177.   friend int    norm_inf(const IMAGE& im1, const IMAGE& im2);
  178.  
  179.  
  180.                 // I/O: write, read, display, print info
  181.                       // Write to a file
  182.                     // "| command name" is OK as a file
  183.                     // name
  184.   void write_pgm(const char * file_name,const char * title = "") const;
  185.                                             // Default writer
  186.   void write(const char * file_name,const char * title = "") const
  187.                   { write_pgm(file_name,title); }
  188.   void display(const char * title) const;
  189.   void info(void) const;        // Print the info about the image
  190.   void print(const char * title) const;    // Print the image as a table
  191.  
  192.  
  193.                 // Clip a square area of the image
  194.   Rectangle    square_of (const int size, const rowcol pos) const;
  195.                 // Clip a rectangular area of the image
  196.                 // specified by the coordinates of
  197.                 // the upper-left and lower-right corners
  198.   Rectangle    rectangle (const rowcol uppleft, const rowcol lowright) const;
  199.  
  200.                 // misc
  201.   volatile void      error(const char* msg) const;
  202. };
  203.  
  204.  
  205. /*
  206.  *------------------------------------------------------------------------
  207.  *        Position specification and operations on it
  208.  */
  209.  
  210. class rowcol {            // Specifying the row/col position
  211.   friend class IMAGE;
  212.   friend class Extrema;
  213.  
  214. protected:
  215.   int row_val;            // both row, col start from 0
  216.   int col_val;
  217.  
  218. public:
  219.                     // Constructors
  220.   rowcol(const int row, const int col)     : row_val(row), col_val(col) {}
  221.   rowcol(void)                : row_val(-1), col_val(-1) {}
  222.  
  223.  ~rowcol() {}
  224.  
  225.   int row(void) const            { return row_val; }
  226.   int col(void) const            { return col_val; }
  227.  
  228.                     // Assignments
  229.                     // Note, that the implementation takes
  230.                     // advantage and is dependent of the
  231.                     // fact the entire rowcol structure
  232.                     // fits into one long word
  233.   rowcol& operator = (const rowcol& pos) 
  234.       { *((long int *)this) = *((long int *)&pos); return *this; }
  235.   rowcol(const rowcol& pos)
  236.       { *((long int *)this) = *((long int *)&pos); }
  237.  
  238.   int operator == (const rowcol& pos)
  239.       { return *((long int *)this) == *((long int *)&pos); }
  240. //    { return memcmp(this,&pos,sizeof(rowcol)); }
  241.  
  242.                     // Offset the current position
  243.   rowcol& operator += (const rowcol& pos)
  244.       { row_val += pos.row_val; col_val += pos.col_val; return *this; }
  245.   rowcol& operator -= (const rowcol& pos)
  246.       { row_val -= pos.row_val; col_val -= pos.col_val; return *this; }
  247.  
  248.   friend inline rowcol operator + (const rowcol& pos1, const rowcol& pos2);
  249.   friend inline rowcol operator - (const rowcol& pos1, const rowcol& pos2);
  250.  
  251.                     // Scale the current position
  252.   rowcol& operator *= (const int scalef)
  253.       { row_val *= scalef; col_val *= scalef; return *this; }
  254.  
  255.   friend inline rowcol operator *  (const rowcol& pos, const int scalef);
  256.   friend inline rowcol operator << (const rowcol& pos, const int shiftf);
  257.   friend inline rowcol operator >> (const rowcol& pos, const int shiftf);
  258. };
  259.  
  260. inline rowcol operator + (const rowcol& pos1, const rowcol& pos2)
  261.         { rowcol rc(pos1.row_val+pos2.row_val, pos1.col_val+pos2.col_val); return rc;}
  262. inline rowcol operator - (const rowcol& pos1, const rowcol& pos2)
  263.         { rowcol rc(pos1.row_val-pos2.row_val, pos1.col_val-pos2.col_val); return rc;}
  264.  
  265. inline rowcol operator *  (const rowcol& pos, const int scalef)
  266.     { rowcol rc(pos.row_val*scalef, pos.col_val*scalef); return rc; }
  267. inline rowcol operator >> (const rowcol& pos, const int shiftf)
  268.     { rowcol rc(pos.row_val >> shiftf, pos.col_val >> shiftf); return rc;}
  269. inline rowcol operator << (const rowcol& pos, const int shiftf)
  270.     { rowcol rc(pos.row_val << shiftf, pos.col_val << shiftf); return rc;}
  271.  
  272.  
  273. class Extrema            // Find min/max values of the (signed) image
  274. {
  275.   GRAY_SIGNED max_value;        // Max pixel value in the image
  276.   GRAY_SIGNED min_value;        // Min pixel value in the image
  277.  
  278. public:
  279.   rowcol      max_pixel;        // Position of the largest pixel
  280.   rowcol      min_pixel;        // Position of the smallest pixel
  281.  
  282.   Extrema(const IMAGE& image);        // Find extremum pixels of the image
  283.   ~Extrema() {}
  284.  
  285.   GRAY_SIGNED max(void) const        { return max_value; }
  286.   GRAY_SIGNED min(void) const        { return min_value; }
  287. };
  288.  
  289.  
  290. /*
  291.  *------------------------------------------------------------------------
  292.  *         Dealing with the rectangular area of the image
  293.  */
  294.  
  295.  
  296. class Rectangle
  297. {
  298.   friend class IMAGE;
  299.  
  300.   IMAGE&    image;        // The image I'm a rectangle of
  301.   int    nrows;        // Dimension of the rectangle
  302.   int    ncols;
  303.   GRAY *    ptr;        // Pointer to the upper left corner of 
  304.                 // the rectangle
  305.   int        inc_to_nextrow;    // inc_to_nextrow = p' - p =
  306.                   //           = image.ncols - ncols
  307.                 // where
  308.                 // p = ptr + ncols points to the pixel
  309.                 // just beyond the current scanline of
  310.                 // the Rectangle
  311.                 // p' = (ptr - col) + image.ncols + col
  312.                 // points to the first pixel of the next
  313.                 // scanline of the rectangtle
  314.                 // col tells the column of the upper left
  315.                 // corner of the rectangle within the image
  316.  
  317.                 // Private constructor
  318.                   // Note these are private constructors to
  319.                 // be used with IMAGE::square_of/rectangle
  320.                 // functions
  321.   Rectangle
  322.     (IMAGE& im, const int size, const rowcol pos);
  323.   Rectangle
  324.     (IMAGE& im, const rowcol uppleft, const rowcol lowright);
  325.  
  326.   public:
  327.                 // Note how to construct square area of
  328.                 // the image 'im':
  329.                 //    im.square_of(10,rowcol(1,5))
  330.                 // and rectangular area
  331.                 //     im.rectangle(rowcol(0,1),rowcol(4,5))
  332.  
  333.   Rectangle (IMAGE& im);        // Treat entire image as a rectangle
  334.   ~Rectangle(void)    {}
  335.                     // Assign a value to all the pixels
  336.                     // in the rectangle area
  337.   Rectangle& operator  = (const int val);
  338.                       // Modify the pixels in the rectangle
  339.                     // area
  340.   friend void operator +=  (const Rectangle& sa, const int val);
  341.   friend void operator -=  (const Rectangle& sa, const int val);
  342.   friend void operator *=  (const Rectangle& sa, const int val);
  343.   friend void operator |=  (const Rectangle& sa, const int val);
  344.   friend void operator &=  (const Rectangle& sa, const int val);
  345.   friend void operator ^=  (const Rectangle& sa, const int val);
  346.   friend void operator <<= (const Rectangle& sa, const int val);
  347.   friend void operator >>= (const Rectangle& sa, const int val);
  348.  
  349.                     // Copy a rectangle a_rect into the
  350.                     // rectangular area of the image
  351.   Rectangle& operator = (const Rectangle& a_rect);
  352.  
  353.                       // Get a total sum of all the pixels
  354.   friend double sum_over(const Rectangle& sa);
  355. };
  356.  
  357. #if 0
  358. /*
  359.  *------------------------------------------------------------------------
  360.  *            Some service procedures
  361.  */
  362.  
  363. inline
  364. int log2(const int n )            // Find a binary logarithm of n
  365. {                                // and check that n is a power of two
  366.  
  367.   register int i,k;
  368.  
  369.   assure(n > 0, "log2: the argument's got to be positive!");
  370.  
  371.   for(k=0,i=1; i < n; k++, i*=2)
  372.     ;
  373.   if( i != n )
  374.     _error("log2: the argument %d has got to be an exact power of two",n);
  375.  
  376.   return k;
  377. }
  378.  
  379. inline
  380. int exp2(const int k)            // Compute 2^k, k>=0
  381. {
  382.   assure(k >= 0, "exp2: the argument may not be negative!");
  383.   if( k > (signed)sizeof(int)*8-1 )
  384.     _error("exp2: the exponent %d is too big",k);
  385.  
  386.   return 1<<k;
  387. }
  388.  
  389. inline                    // return b * round( a/b )
  390. int round_to_even_multiple(const int a, const int b)
  391. {
  392.   assert( b > 0 );
  393.   register int rem = a % b;
  394.   if( 2*rem < b )
  395.     return a - rem;
  396.   else
  397.     return a + b - rem;
  398. }
  399. #endif
  400.  
  401. /*
  402.  *------------------------------------------------------------------------
  403.  *            Inline Image Procedures
  404.  */
  405.  
  406. inline IMAGE::IMAGE(const int no_rows, const int no_cols, const int depth)
  407. {
  408.   allocate(no_rows,no_cols,depth);
  409. }
  410.  
  411.                     // Make a new image like the
  412. inline IMAGE::IMAGE(const IMAGE& old)    // old one
  413. {
  414.   allocate(old.nrows,old.ncols,old.bits_per_pixel);
  415. }
  416.  
  417. inline GRAY& IMAGE::operator () (const int row, const int col) const
  418. {
  419.   is_valid();
  420.   if( row >= nrows || row < 0 )
  421.     _error("Row index %d is out of image boundaries [0,%d]",row,nrows-1);
  422.   if( col >= ncols || col < 0 )
  423.     _error("Col index %d is out of image boundaries [0,%d]",col,ncols-1);
  424.   
  425.   return (scanrows[row])[col];
  426. }
  427.  
  428. inline GRAY& IMAGE::operator () (const rowcol pos) const
  429. {
  430.   return operator()(pos.row(),pos.col());
  431. }
  432.  
  433.                     // Make sure the pos is within the
  434.                     // image
  435. inline void  IMAGE::sure_within(const rowcol pos) const
  436. {
  437.   is_valid();
  438.   if( pos.row() >= nrows || pos.row() < 0 )
  439.     _error("Row index %d is out of image boundaries [0,%d]",pos.row(),nrows-1);
  440.   if( pos.col() >= ncols || pos.col() < 0 )
  441.     _error("Col index %d is out of image boundaries [0,%d]",pos.col(),ncols-1);
  442. }
  443.  
  444. inline IMAGE& IMAGE::clear(void)    // Clean the image
  445. {
  446.   is_valid();
  447.   memset(pixels,0,npixels*sizeof(GRAY));
  448.   return *this;
  449. }
  450.  
  451. inline IMAGE& IMAGE::invert(void)    // Invert the image
  452. {
  453.   is_valid();
  454.   return (*this ^= ((1<<bits_per_pixel)-1));
  455. }
  456.  
  457. inline void are_compatible(const IMAGE& im1, const IMAGE& im2)
  458. {
  459.   im1.is_valid();
  460.   im2.is_valid();
  461.   
  462.   if( im1.ncols != im2.ncols || im1.nrows != im2.nrows )
  463.     _error("The image %dx%d and the image %dx%d have different sizes",
  464.        im1.nrows,im1.ncols,im2.nrows,im2.ncols);
  465. }
  466.  
  467. inline int  operator == (const IMAGE& im1, const IMAGE& im2)
  468. {
  469.   return identical(im1,im2);
  470. }
  471.  
  472.  
  473.                 // Construct a square rectangle
  474. inline Rectangle::Rectangle
  475.     (IMAGE& im, const int sq_size, const rowcol pos)
  476.     : image(im), nrows(sq_size), ncols(sq_size)
  477. {
  478.   image.is_valid();
  479.  
  480.   if( pos.row() >= image.nrows || pos.row() < 0 ||
  481.       pos.row() + nrows > image.nrows ||
  482.       pos.col() >= image.ncols || pos.col() < 0 ||
  483.       pos.col() + ncols > image.ncols )
  484.     _error("Square area (left upper point [%d,%d], size %d)\n"
  485.        "is not within the image %dx%d",
  486.        pos.row(),pos.col(),sq_size,image.nrows,image.ncols);
  487.  
  488.   ptr  = &(image.scanrows[pos.row()][pos.col()]);
  489.   inc_to_nextrow = image.ncols - ncols;
  490. }
  491.  
  492.                 // Clip a square area from the image
  493. inline Rectangle IMAGE::square_of(const int size, const rowcol pos) const
  494. { Rectangle c((IMAGE)*this, size, pos); return c; }
  495.  
  496.  
  497.                 // Make a rectangle with upper left corner
  498.                 // at uppleft position and lower right corner
  499.                 // at lowright position
  500. inline Rectangle::Rectangle
  501.     (IMAGE& im, const rowcol uppleft, const rowcol lowright)
  502.     : image(im), nrows(lowright.row()-uppleft.row()+1), 
  503.                  ncols(lowright.col()-uppleft.col()+1)
  504. {
  505.   image.is_valid();
  506.  
  507.   image.sure_within(uppleft);
  508.   image.sure_within(lowright);
  509.  
  510.   ptr  = &(image.scanrows[uppleft.row()][uppleft.col()]);
  511.   inc_to_nextrow = image.ncols - ncols;
  512. }
  513.  
  514.  
  515.                 // Clip a rectangular area from the image
  516. inline Rectangle IMAGE::rectangle(const rowcol uppleft,const rowcol lowright)
  517.                  const
  518. { Rectangle c((IMAGE)*this, uppleft, lowright); return c; }
  519.  
  520.  
  521.                 // Treat the entire image as a rectangular area
  522. inline Rectangle::Rectangle (IMAGE& im)
  523.     : image(im), nrows(im.nrows), ncols(im.ncols)
  524. {
  525.   image.is_valid();
  526.  
  527.   ptr  = image.pixels;
  528.   inc_to_nextrow = 0;
  529. }
  530.  
  531.  
  532. #endif
  533.